/* eslint-disable no-restricted-syntax */
/* eslint-disable no-unused-expressions */
import nodeConfig from './config.js';

const isEmptyArray = data => (Array.isArray(data) ? data.length === 0 : true);
export class NodeUtils {
    /**
     * 自动生成节点唯一id
     * @returns id字符串
     */
    static idGenerator(type) {
        return `${type}_${genID(6)}`;
    }

    /**
     * 判断节点类型
     * @param {Node} node - 节点数据
     * @returns Boolean
     */
    static isConditionNode(node) {
        return node && node.type === 'condition';
    }

    static isCopyNode(node) {
        return node && node.type === 'copy';
    }

    static isStartNode(node) {
        return node && node.type === 'start';
    }

    static isApproverNode(node) {
        return node && node.type === 'approver';
    }

    /**
     * 创建指定节点
     * @param { String } type - 节点类型
     * @param { Object } previousNodeId - 父节点id
     * @returns { Object } 节点数据
     */
    static createNode(type, previousNodeId) {
        const res = JSON.parse(JSON.stringify(nodeConfig[type]));
        res.nodeId = this.idGenerator(type);
        res.prevId = previousNodeId;
        return res;
    }

    /**
     * 获取指定节点的父节点（前一个节点）
     * @param { String } prevId - 父节点id
     * @param { Object } processData - 流程图全部数据
     * @returns { Object } 父节点
     */
    static getPreviousNode(prevId, processData) {
        if (processData.nodeId === prevId) return processData;
        if (processData.childNode) {
            const r1 = this.getPreviousNode(prevId, processData.childNode);
            if (r1) {
                return r1;
            }
        }
        if (processData.conditionNodes) {
            for (const c of processData.conditionNodes) {
                const r2 = this.getPreviousNode(prevId, c);
                if (r2) {
                    return r2;
                }
            }
        }
        return null;
    }

    /**
     * 获取指定的当前节点
     * @param { String } nodeId - 当前节点id
     * @param { Object } processData - 流程图全部数据
     * @returns { Object } 当前节点
     */
    static getCurrentNode(nodeId, processData) {
        if (processData.nodeId === nodeId) return processData;
        if (processData.childNode) {
            const r1 = this.getCurrentNode(nodeId, processData.childNode);
            if (r1) {
                return r1;
            }
        }
        if (processData.conditionNodes) {
            for (const c of processData.conditionNodes) {
                const r2 = this.getCurrentNode(nodeId, c);
                if (r2) {
                    return r2;
                }
            }
        }
        return null;
    }

    /**
     * 删除节点
     * @param { Object  } nodeData - 被删除节点的数据
     * @param { Object  } processData - 流程图的所有节点数据
     */
    static deleteNode(nodeData, processData) {
        const prevNode = this.getPreviousNode(nodeData.prevId, processData);
        const concatChild = (prev, delNode) => {
            prev.childNode = delNode.childNode;
            isEmptyArray(prev.conditionNodes) && (prev.conditionNodes = delNode.conditionNodes);
            prev.childNode && (prev.childNode.prevId = prev.nodeId);
            // eslint-disable-next-line no-return-assign
            prev.conditionNodes && prev.conditionNodes.forEach(c => (c.prevId = prev.nodeId));
        };
        if (this.isConditionNode(nodeData)) {
            const cons = prevNode.conditionNodes;
            const index = cons?.findIndex(c => c.nodeId === nodeData.nodeId);
            if (cons.length > 2) {
                cons.splice(index, 1);
            } else {
                const anotherCon = cons[+!index];
                delete prevNode.conditionNodes;
                if (prevNode.childNode) {
                    let endNode = anotherCon;
                    while (endNode.childNode) {
                        endNode = endNode.childNode;
                    }
                    endNode.childNode = prevNode.childNode;
                    endNode.childNode.prevId = endNode.nodeId;
                }
                concatChild(prevNode, anotherCon);
            }
            // 重新编排优先级
            // eslint-disable-next-line no-return-assign
            cons.forEach((c, i) => (c.properties.priority = i));
            return;
        }
        concatChild(prevNode, nodeData);
    }

    /**
     * 添加审计节点（普通节点 approver）
     * @param { Object } data - 目标节点数据，在该数据节点之后添加审计节点
     * @param { Object } isBranchAction - 目标节点数据，是否是条件分支
     * @param { Object } newChildNode - 传入的新的节点 用户操作均为空  删除操作/添加抄送人 会传入该参数 以模拟添加节点
     */
    static addApprovalNode(data, isBranchAction, newChildNode = undefined) {
        const oldChildNode = data.childNode;
        newChildNode = newChildNode || this.createNode('approver', data.nodeId);
        data.childNode = newChildNode;
        if (oldChildNode) {
            newChildNode.childNode = oldChildNode;
            oldChildNode.prevId = newChildNode.nodeId;
        }
        const { conditionNodes } = data;
        if (Array.isArray(conditionNodes) && !isBranchAction && conditionNodes.length) {
            newChildNode.conditionNodes = conditionNodes.map(c => {
                c.prevId = newChildNode.nodeId;
                return c;
            });
            delete data.conditionNodes;
        }
    }

    static addCopyNode(data, isBranchAction) {
        // 复用addApprovalNode  因为抄送人和审批人基本一致
        this.addApprovalNode(data, isBranchAction, this.createNode('copy', data.nodeId));
    }

    /**
     * 添加条件节点 condition 通过点击添加条件进入该操作
     * @param { Object } data - 目标节点所在分支数据，在该分支最后添加条件节点
     */
    static appendConditionNode(data) {
        const conditions = data.conditionNodes;
        const node = this.createNode('condition', data.nodeId);
        const defaultNodeIndex = conditions.findIndex(subNode => subNode.properties.isDefault);
        node.properties.title += conditions.length + 1;
        node.properties.priority = conditions.length;
        if (defaultNodeIndex > -1) {
            conditions.splice(-1, 0, node); // 插在倒数第二个
            // 更新优先级
            node.properties.priority = conditions.length - 2;
            conditions[conditions.length - 1].properties.priority = conditions.length - 1;
        } else {
            conditions.push(node);
        }
    }

    /**
     * 添加条件分支 branch
     * @param { Object } data - 目标节点所在节点数据，在该节点最后添加分支节点
     */
    static appendBranch(data) {
        // isBottomBtnOfBranch 用户点击的是分支树下面的按钮
        const nodeData = data;
        const conditionNodes = [
            this.createNode('condition', nodeData.nodeId),
            this.createNode('condition', nodeData.nodeId)
        ].map((c, i) => {
            c.properties.title += i + 1;
            c.properties.priority = i;
            return c;
        });
        nodeData.conditionNodes = conditionNodes;
    }

    /**
     * 重设节点优先级（条件节点）
     * @param {Node} cnode - 当前节点
     * @param {Number} oldIndex - 旧的索引
     * @param {Node} processData - 整个流程图节点数据
     */
    static resortPrioByCNode(cnode, oldIndex, processData) {
        const prevNode = this.getPreviousNode(cnode.prevId, processData);
        const newIndex = cnode.properties.priority;
        const arr = [...prevNode.conditionNodes];
        const oldNode = arr.splice(oldIndex, 1);
        arr.splice(newIndex, 0, ...oldNode);
        // 修改属性
        arr.map((item, index) => {
            const obj = item;

            if (cnode.properties.isDefault) {
                obj.properties.isDefault = newIndex === index;
            } else if (index === newIndex) {
                obj.properties.isDefault = false;
            }

            obj.properties.priority = index;
            return obj;
        });
        prevNode.conditionNodes = [...arr];
    }

    /**
     *
     * @param {Array} condtionarr -条件控件数组
     * @param {*} processData - 整个流程图节点数据
     */
    static updateFormOperate(condtionarr = [], processData) {
        const result = { isStartNodeChange: null, isApproveNodeChange: null };
        if (condtionarr.length > 0) {
            // 已使用的条件
            const usedArr = condtionarr.filter(item => item.isUsed);

            const loop = node => {
                if (this.isStartNode(node)) {
                    if (node.properties.formOperates) {
                        node.properties.formOperates.forEach(item => {
                            if (
                                usedArr.findIndex(subItem => subItem.formId === item.formId) > -1 &&
                                item.formOperate !== 2
                            ) {
                                item.formOperate = 2;
                                result.isStartNodeChange = true;
                            }
                        });
                    }
                }
                if (node.childNode) {
                    if (this.isApproverNode(node.childNode)) {
                        if (node.childNode.properties.formOperates) {
                            node.childNode.properties.formOperates.forEach(item => {
                                if (
                                    usedArr.findIndex(subItem => subItem.formId === item.formId) > -1 &&
                                    item.formOperate === 2
                                ) {
                                    item.formOperate = 1;
                                    result.isApproveNodeChange = true;
                                }
                                return item;
                            });
                        }
                    }
                    loop(node.childNode);
                }
                if (node.conditionNodes && node.conditionNodes.length > 0) {
                    node.conditionNodes.forEach(item => {
                        if (item.childNode) {
                            loop(item.childNode);
                        }
                    });
                }
            };
            loop(processData);
        }
        return result;
    }

    /**
     * 校验单个节点必填项完整性
     * @param {Node} node - 节点数据
     */
    static checkNode(node) {
        let valid = true;
        const props = node.properties;
        this.isConditionNode(node) && !props.isDefault && isEmptyArray(props.conditions) && (valid = false);
        // this.isApproverNode(node) && isEmptyArray(props.approvers) && (valid = false);
        this.isApproverNode(node) &&
            !props.candidateUsers &&
            !(props.candidateUsers && props.candidateUsers.length === 0) &&
            (valid = false);
        this.isCopyNode(node) && isEmptyArray(props.copyUsers) && (valid = false);
        return valid;
    }

    /**
     * 判断所有节点是否信息完整
     * @param {Node} processData - 整个流程图数据
     * @returns {Boolean}
     */
    static checkAllNode(processData) {
        let valid = true;
        const loop = (node, callback) => {
            !this.checkNode(node) && callback();
            if (node.childNode) loop(node.childNode, callback);
            if (!isEmptyArray(node.conditionNodes)) {
                node.conditionNodes.forEach(n => loop(n, callback));
            }
        };
        loop(processData, () => {
            valid = false;
        });
        return valid;
    }

    /**
     * 设置默认条件节点后修改当前兄弟节点
     * @param {Node} cnode - 当前节点
     * @param {Node} processData - 整个流程图节点数据
     */
    static resetDefaultConditions(cnode, processData) {
        const prevNode = this.getPreviousNode(cnode.prevId, processData);
        const arr = [...prevNode.conditionNodes];
        // 修改属性
        arr?.map(item => {
            const obj = item;

            if (obj.properties.isDefault === true) {
                obj.content = '其他条件进入此流程';
                obj.properties.conditions = [];
            } else if (obj.properties.conditions.length === 0) {
                obj.content = '请设置条件';
            }
            return obj;
        });
        prevNode.conditionNodes = [...arr];
    }

    /**
     * 判断流程是否完整
     * @param {Node} processData - 整个流程图数据
     * @returns {Boolean}
     */
    static checkIntegrity(processData) {
        let valid = false;

        const loop = (node, callback) => {
            if (node.childNode) {
                callback();
                return;
            }
            if (node.childNode) loop(node.childNode, callback);
            if (!isEmptyArray(node.conditionNodes)) {
                node.conditionNodes.forEach(n => loop(n, callback));
            }
        };
        loop(processData, () => {
            valid = true;
        });
        return valid;
    }
}

/**
 *
 * 生成唯一id
 */
export function genID(length) {
    return Number(
        Math.random()
            .toString()
            .substr(3, length) + Date.now()
    ).toString(36);
}

/**
 * 添模拟数据
 */
export function getMockData() {
    const startNode = NodeUtils.createNode('start');
    startNode.childNode = NodeUtils.createNode('approver', startNode.nodeId);
    return startNode;
}
